import '@/assets/mapbox/libs/draw/mapbox-gl-draw.css'
import MapBoxDraw from '@/assets/mapbox/libs/draw/mapbox-gl-draw.js'

import * as turf from '@turf/turf';
import PlotBaseClass from '@/assets/js/plot/AreaPlotBase.js'

/**
         * Package: StraightArrow
         * 斜箭头：1.控制点组；2.构成的所有点部分
         * 方法：用于通过控制点计算箭头的所有绘制点
         */
const doubleClickZoom = {
  enable: ctx => {
    setTimeout(() => {
      // First check we've got a map and some context.
      if (
        !ctx.map ||
        !ctx.map.doubleClickZoom ||
        !ctx._ctx ||
        !ctx._ctx.store ||
        !ctx._ctx.store.getInitialConfigValue
      )
        return;
      // Now check initial state wasn't false (we leave it disabled if so)
      if (!ctx._ctx.store.getInitialConfigValue("doubleClickZoom")) return;
      ctx.map.doubleClickZoom.enable();

      //state.controlPoints =[];
    }, 0);
  },
  disable(ctx) {
    setTimeout(() => {
      if (!ctx.map || !ctx.map.doubleClickZoom) return;
      // Always disable here, as it's necessary in some cases.
      ctx.map.doubleClickZoom.disable();
    }, 0);
  }
};

const DrawDiagonalArrow = {
  // When the mode starts this function will be called.
  onSetup: function(opts) {
    const DiagonalArrow = this.newFeature({
      type: "Feature",
      properties: {},
      geometry: {
        type: "Polygon",
        coordinates: [[]]
      }
    });
    this.controlPoints = [];

    this.addFeature(DiagonalArrow);
    this.clearSelectedFeatures();
    doubleClickZoom.disable(this);
    this.updateUIClasses({ mouse: "add" });
    this.setActionableState({
      trash: true
    });
    return {
      DiagonalArrow
    };
  },
 // controlPoints:[],
  //双击结束
  clickOnVertex:function(state, e) {
    if (
      state.controlPoints &&
      state.controlPoints[state.controlPoints.length-1].x !== e.lngLat.lng &&
      state.controlPoints[state.controlPoints.length-1].y !== e.lngLat.lat
    ) {
      this.updateUIClasses({ mouse: "pointer" }); 
      this.changeMode("simple_select", { featuresId: state.DiagonalArrow.id });
    }    
  },
  // support mobile taps
  onTap: function(state, e) {
    // emulate 'move mouse' to update feature coords
    if (state.controlPoints) this.onMouseMove(state, e);
    // emulate onClick
    this.onClick(state, e);
  },
  // Whenever a user clicks on the map, Draw will call `onClick`（箭头的起始点）
  onClick: function(state, e) {
    // if state.startPoint exist, means its second click
    //change to  simple_select mode（继续画，双击结束）
    var point = this.newFeature({
    type: 'Feature',
    properties: {
      
    },
    geometry: {
      type: 'Point',
      coordinates: [e.lngLat.lng, e.lngLat.lat]
    }
  });
    //this.addFeature(point); //显示点
    //双击结束绘制
   if (
      state.controlPoints &&
      state.controlPoints[state.controlPoints.length-1].x == e.lngLat.lng &&
      state.controlPoints[state.controlPoints.length-1].y == e.lngLat.lat
    ) {
      this.updateUIClasses({ mouse: "pointer" }); 
      this.changeMode("simple_select", { featuresId: state.DiagonalArrow.id });

      this.controlPoints = [];
    } 
    //const controlPoints = [{x:e.lngLat.lng, y:e.lngLat.lat}];
     this.controlPoints.push({x:e.lngLat.lng, y:e.lngLat.lat});//箭头的控制点
     state.controlPoints = this.controlPoints;
  },
  onMouseMove: function(state, e) {
    // if startPoint, update the feature coordinates, using the bounding box concept
    // we are simply using the startingPoint coordinates and the current Mouse Position
    // coordinates to calculate the bounding box on the fly, which will be our rectangle  有起始控制点，通过鼠标停留的改点计算箭头样式显示在地图上，随着移动更新
    if (state.controlPoints) {
       if(state.controlPoints.length  != 0 ){
        const arrowpnts = PlotBaseClass.cloneControlPoints(state.controlPoints);
        arrowpnts.push({x:e.lngLat.lng, y:e.lngLat.lat})
        const sevenpnts =  this.calculateParts(arrowpnts);
         
        for(var i=0;i < sevenpnts.length;i++){

           // state.straightArrow.coordinates.push([ sevenpnts[i].x,sevenpnts[i].y]);
            
           state.DiagonalArrow.updateCoordinate("0."+i, sevenpnts[i].x, sevenpnts[i].y ); 
           //state.straightArrow.updateCoordinate("0.2", e.lngLat.lng, e.lngLat.lat); // maxX, maxY
         }
       }
      else{
        //没有控制点的情况
    }
    }
  },
  // keyboard triger while focused on the map：ESC:27
  onKeyUp: function(state, e) {
    if (e.keyCode === 27) return this.changeMode("simple_select");
  },
  onStop: function(state) {
    doubleClickZoom.enable(this);
    this.updateUIClasses({ mouse: "none" });
    this.activateUIButton();

    // check to see if we've deleted this feature
    if (this.getFeature(state.DiagonalArrow.id) === undefined) return;

    //remove last added coordinate 移除最后一个点
   // state.straightArrow.removeCoordinate("0.4"); 
    if (state.DiagonalArrow.isValid()) {
      this.map.fire("draw.create", {
        features: [state.DiagonalArrow.toGeoJSON()]
      });
    } else {
      this.deleteFeature([state.DiagonalArrow.id], { silent: true });
      this.changeMode("simple_select", {}, { silent: true });
    }
    this.controlPoints = [];
  },
  toDisplayFeatures: function(state, geojson, display) {
    const isActivePolygon = geojson.properties.id === state.DiagonalArrow.id;
    geojson.properties.active = isActivePolygon ? "true" : "false";
    if (!isActivePolygon) return display(geojson);
  
    // Only render the rectangular polygon if it has the starting point
    if (!state.controlPoints) return;
    return display(geojson);
  },
  onTrash: function(state) {
    this.deleteFeature([state.DiagonalArrow.id], { silent: true });
    this.changeMode("simple_select");
  },


   /**
         * Method: calculateParts
         * 用于通过控制点计算箭头的所有绘制点
         */
    calculateParts : function(controlPoints){
            //判定少于两个点或者为空，则直接返回
            if(controlPoints == null || controlPoints.length < 2)
            {
                return;
            }
            //判断如果为两个点，且两个点重合时也直接返回.equals
            if(controlPoints.length == 2 && controlPoints[0] == controlPoints[1])
            {
                return;
            }
            //清空原有的所有点
            this.components = [];
            //计算只有两个点时，即直的斜箭头
            if(controlPoints.length == 2)
            {
              return  this.calculateTwoPoints(controlPoints);
            }
            //计算有三个或三个以上的点时，即弯曲的斜箭头
            else
            {
               return this.calculateMorePoints(controlPoints);
            }
        },
         
        /**
         * Method: calculateTwoPoints
         * 计算两个控制点时直箭头的所有绘制点
         * 两个控制点的直箭头绘制点只需要7个就可以构成
         */
    calculateTwoPoints:function (controlPoints){
            this._ratio = 6;
            var controlPois = PlotBaseClass.cloneControlPoints(controlPoints);

            //取出首尾两个点
            var pointS = controlPois[0];
            var pointE = controlPois[1];
            //计算箭头总长度
            var l = Math.sqrt((pointE.y-pointS.y)*(pointE.y-pointS.y)+(pointE.x-pointS.x)*(pointE.x-pointS.x));
            //计算直箭头的宽
            var w = l/this._ratio;

            //计算三角形的底边中心点坐标
            var x_ = pointS.x + (pointE.x - pointS.x)*(this._ratio-1)/this._ratio;
            var y_ = pointS.y + (pointE.y - pointS.y)*(this._ratio-1)/this._ratio;
            var point_o = {x:x_,y:y_};

            //计算
            var v_lr_ = this.calculateVector({x:pointE.x-pointS.x,y:pointE.y-pointS.y},Math.PI/2,w/2);
            //获取左边尾部向量
            var v_l_ = v_lr_[0];
            //获取右边尾部向量
            var v_r_ = v_lr_[1];
            //获取左边尾部点
            var point_l = {x:v_l_.x+pointS.x,y:v_l_.y+pointS.y};
            //获取右边尾部点
            var point_r = {x:v_r_.x+pointS.x,y:v_r_.y+pointS.y};

            var point_h_l = {x:v_l_.x/this._ratio+x_,y:v_l_.y/this._ratio+y_};
            var point_h_r = {x:v_r_.x/this._ratio+x_,y:v_r_.y/this._ratio+y_};

            //计算三角形左边点
            var point_a_l = {x:point_h_l.x*2-point_h_r.x,y:point_h_l.y*2-point_h_r.y};
            //计算三角形右边点
            var point_a_r = {x:point_h_r.x*2-point_h_l.x,y:point_h_r.y*2-point_h_l.y};

            return [point_l,point_h_l,point_a_l,pointE,point_a_r,point_h_r,point_r,point_l];           
            //this.components.push(new SuperMap.Geometry.LinearRing([point_l,point_h_l,point_a_l,pointE,point_a_r,point_h_r,point_r]));
        },

         /**
         * Method: calculateVector
         * 计算和基准向量v夹角为a、长度为d的目标向量（理论上有两个，一左一右）
         *
         * Parameters:
         * v - {<Point>} 基准向量
         * a - {Number} 目标向量和基准向量的夹角，默认为90度，这里的单位使用弧度
         * d - {Number} 目标向量的长度，即模，默认为1，即单位向量
         *
         * Returns:
         * {Array(<Point>)} 回目标向量数组（就两个向量，一左一右）:Point
         */
        calculateVector: function(v, a, d){
            if(!a) a =  Math.PI/2;
            if(!d) d = 1;

            //定义目标向量的头部   x 坐标
            var x_1;
            var x_2;
            //定义目标向量的头部   y 坐标
            var y_1;
            var y_2;
            //定义目标向量，一左一右
            var v_l;
            var v_r;

            //计算基准向量v的模
            var d_v = Math.sqrt(v.x*v.x+v.y*v.y);

            //基准向量的斜率为0时，y值不能作为除数，所以需要特别处理
            if(v.y == 0)
            {
                //计算x,会有两个值
                x_1 = x_2 = d_v*d*Math.cos(a)/v.x;
                //根据v.x的正负判断目标向量的左右之分
                if(v.x>0)
                {
                    //计算y
                    y_1 = Math.sqrt(d*d-x_1*x_1);
                    y_2 = -y_1;
                }
                else if (v.x < 0)
                {
                    //计算y
                    y_2 = Math.sqrt(d*d-x_1*x_1);
                    y_1 = -y_2;
 
                }
                v_l = {x:x_1,y:y_1};
                v_r = {x:x_2,y:y_2};
            }
            //此为大多数情况
            else
            {
                //转换为y=nx+m形式
                var n = -v.x/v.y;
                var m = d*d_v*Math.cos(a)/v.y;
                //
                //x*x + y*y = d*d
                //转换为a*x*x + b*x + c = 0
                var a = 1+n*n;
                var b = 2*n*m;
                var c = m*m - d*d;
                //计算x,会有两个值
                x_1 = (-b - Math.sqrt(b*b-4*a*c))/(2*a);
                x_2 = (-b + Math.sqrt(b*b-4*a*c))/(2*a);
                //计算y
                y_1 = n*x_1 + m;
                y_2 = n*x_2 + m;
                //当向量向上时
                if(v.y>=0)
                {
                    v_l = {x:x_1,y:y_1};
                    v_r = {x:x_2,y:y_2};
                }
                //当向量向下时
                else if(v.y < 0)
                {
                    v_l = {x:x_2,y:y_2};
                    v_r = {x:x_1,y:y_1};
                }
            }
            return [v_l,v_r];
        },

         /**
         * Method: calculateMorePoints
         * 计算三个或三个以上的控制点时的所有绘制点
         * 由于中间的控制点之间会进行差值，产生曲线效果，所以所需绘制点会很多
         * 这里使用的思想是将所有用户控制点连接起来形成一条折线段，
         * 然后在拐角进行曲线化处理（二次贝塞尔曲线差值），就形成了效果比较好的箭头
         *
         */
        calculateMorePoints: function(controlPoints){
            var controlPois = PlotBaseClass.cloneControlPoints(controlPoints);
            this._ratio = 6;
           
            //计算箭头总长度
            var l = 0;
            //计算直箭头的宽
            var w = 0;
            for(var i = 0; i < controlPois.length - 1; i++)
            {
                //取出首尾两个点
                var pointS = controlPois[i];
                var pointE = controlPois[i+1];
                l += Math.sqrt((pointE.y-pointS.y)*(pointE.y-pointS.y)+(pointE.x-pointS.x)*(pointE.x-pointS.x));
            }
            w = l/this._ratio;

            var a = Math.atan(w/(2*l));

            //定义左右控制点集合
            var points_C_l = [];
            var points_C_r = [];
            //定义尾部左右的起始点
            var point_t_l = {};
            var point_t_r = {};


            //计算中间的所有交点
            for(var j = 0; j < controlPois.length-2; j++)
            {
                var pointU_1 = controlPois[j];//第一个用户传入的点
                var pointU_2 = controlPois[j+1];//第二个用户传入的点
                var pointU_3 = controlPois[j+2];//第三个用户传入的点

                //计算向量
                var v_U_1_2 = {x:pointU_2.x-pointU_1.x,y:pointU_2.y-pointU_1.y};
                var v_U_2_3 = {x:pointU_3.x-pointU_2.x,y:pointU_3.y-pointU_2.y};


                //定义左边第一个控制点
                var point_l_1 = {};
                //定义右边第一个控制点
                var point_r_1 = {};
                //如果j=0时，左右第一个控制点需要计算
                if(j == 0)
                {
                    var v_lr_ = this.calculateVector(v_U_1_2,Math.PI/2,w/2);
                    //获取左边尾部点
                    var v_l_ = v_lr_[0];
                    //获取右边尾部点
                    var v_r_ = v_lr_[1];
                    //获取左边尾部点
                    point_t_l = point_l_1 = {x:v_l_.x+pointU_1.x,y:v_l_.y+pointU_1.y};
                    //获取右边尾部点
                    point_t_r = point_r_1 = {x:v_r_.x+pointU_1.x,y:v_r_.y+pointU_1.y};
                }
                //否则获取上一次的记录
                else
                {
                    point_l_1 = points_C_l[points_C_l.length-1];
                    point_r_1 = points_C_r[points_C_r.length-1];
                }
                var v_lr = this.calculateVector(v_U_1_2,a,1);
                //这里的向量需要反过来
                //获取左边向量
                var v_l = v_lr[1];
                //获取右边向量
                var v_r = v_lr[0];
                //定义角平分线向量
                var v_angularBisector = PlotBaseClass.calculateAngularBisector({x:-v_U_1_2.x,y:-v_U_1_2.y},v_U_2_3);
                //求交点
                //计算左边第二个控制点
                var point_l_2 = this.calculateIntersection(v_l,v_angularBisector,point_l_1,pointU_2);
                var point_r_2 = this.calculateIntersection(v_r,v_angularBisector,point_r_1,pointU_2);


                //添加后面的拐角控制点
                points_C_l.push({x:(point_l_1.x+point_l_2.x)/2,y:(point_l_1.y+point_l_2.y)/2});
                points_C_l.push(point_l_2);
                points_C_r.push({x:(point_r_1.x+point_r_2.x)/2,y:(point_r_1.y+point_r_2.y)/2});
                points_C_r.push(point_r_2);
            }

            //进入计算头部
            //计算一下头部的长度
            var pointU_E2 = controlPois[controlPois.length-2];//倒数第二个用户点
            var pointU_E1 = controlPois[controlPois.length-1];//最后一个用户点
            var head_d = Math.sqrt((pointU_E2.x-pointU_E1.x)*(pointU_E2.x-pointU_E1.x) + (pointU_E2.y-pointU_E1.y)*(pointU_E2.y-pointU_E1.y));
            //定义头部的左右两结束点
            var point_h_l = {};
            var point_h_r = {};
            //三角形左右两点数组
            var point_lr_t = [];
            //定义曲线最后一个控制点，也就是头部结束点和最后一个拐角点的中点
            var point_C_l_e = {};
            var point_C_r_e = {};
            //定义三角形的左右两个点
            var point_triangle_l = {};
            var point_triangle_r = {};

            //获取当前的最后的控制点，也就是之前计算的拐角点
            var point_C_l_eq = points_C_l[points_C_l.length-1];
            var point_C_r_eq = points_C_r[points_C_r.length-1];
            //申明三角形的两边向量
            var v_l_t = {};
            var v_r_t = {};
            //三角的高度都不够
            if(head_d <= w)
            {
                point_lr_t = this.calculateVector({x:pointU_E1.x-pointU_E2.x,y:pointU_E1.y-pointU_E2.y},Math.PI/2,w/2);
                //获取三角形左右两个向量
                v_l_t = point_lr_t[0];
                v_r_t = point_lr_t[1];

                point_h_l = {x:v_l_t.x/this._ratio+pointU_E2.x,y:v_l_t.y/this._ratio+pointU_E2.y};
                point_h_r = {x:v_r_t.x/this._ratio+pointU_E2.x,y:v_r_t.y/this._ratio+pointU_E2.y};
                //计算三角形的左右两点
                point_triangle_l = {x:point_h_l.x*2-point_h_r.x,y:point_h_l.y*2-point_h_r.y};
                point_triangle_r = {x:point_h_r.x*2-point_h_l.x,y:point_h_r.y*2-point_h_l.y};

                //计算最后的控制点
                point_C_l_e = {x:(point_C_l_eq.x+point_h_l.x)/2,y:(point_C_l_eq.y+point_h_l.y)/2};
                point_C_r_e = {x:(point_C_r_eq.x+point_h_r.x)/2,y:(point_C_r_eq.y+point_h_r.y)/2};

                //添加最后的控制点（中心点）
                points_C_l.push(point_C_l_e);
                points_C_r.push(point_C_r_e);
            }
            //足够三角的高度
            else
            {
                //由于够了三角的高度，所以首先去掉三角的高度

                //计算向量
                var v_E2_E1 = {x:pointU_E1.x-pointU_E2.x,y:pointU_E1.y-pointU_E2.y};
                //取模
                var v_E2_E1_d = Math.sqrt(v_E2_E1.x*v_E2_E1.x+v_E2_E1.y*v_E2_E1.y);
                //首先需要计算三角形的底部中心点
                var point_c = {x:pointU_E1.x-v_E2_E1.x*w/v_E2_E1_d,y:pointU_E1.y-v_E2_E1.y*w/v_E2_E1_d};

                //计算出在三角形上底边上头部结束点
                point_lr_t = this.calculateVector({x:pointU_E1.x-point_c.x,y:pointU_E1.y-point_c.y},Math.PI/2,w/2);
                //获取三角形左右两个向量
                v_l_t = point_lr_t[0];
                v_r_t = point_lr_t[1];

                point_h_l = {x:v_l_t.x/this._ratio+point_c.x,y:v_l_t.y/this._ratio+point_c.y};
                point_h_r = {x:v_r_t.x/this._ratio+point_c.x,y:v_r_t.y/this._ratio+point_c.y};
                //计算三角形的左右两点
                point_triangle_l = {x:point_h_l.x*2-point_h_r.x,y:point_h_l.y*2-point_h_r.y};
                point_triangle_r = {x:point_h_r.x*2-point_h_l.x,y:point_h_r.y*2-point_h_l.y};

                //计算最后的控制点
                point_C_l_e = {x:(point_C_l_eq.x+point_h_l.x)/2,y:(point_C_l_eq.y+point_h_l.y)/2};
                point_C_r_e = {x:(point_C_r_eq.x+point_h_r.x)/2,y:(point_C_r_eq.y+point_h_r.y)/2};

                //添加最后的控制点（中心点）
                points_C_l.push(point_C_l_e);
                points_C_r.push(point_C_r_e);
            }
            //使用控制点计算差值
            //计算贝塞尔的控制点
            var points_BC_l =PlotBaseClass.calculatePointsFBZ2(points_C_l);
            var points_BC_r =PlotBaseClass.calculatePointsFBZ2(points_C_r);
            //组合左右点集和三角形三个点
            var pointsR = [point_t_l];
            //首先连接左边的差值曲线
            pointsR = pointsR.concat(points_BC_l);
            //添加左边头部结束点
            pointsR.push(point_h_l);
            //添加三角形左边点
            pointsR.push(point_triangle_l);
            //添加三角形顶点
            pointsR.push(pointU_E1);
            //添加三角形右边点
            pointsR.push(point_triangle_r);
            //添加右边头部结束点
            pointsR.push(point_h_r);
            //合并右边的所有点
            for(var k = points_BC_r.length-1; k>=0; k--)
            {
                pointsR.push(points_BC_r[k]);
            }
            //添加右边尾部起始点
            pointsR.push(point_t_r);
           return pointsR
           //this.components.push(new SuperMap.Geometry.LinearRing(pointsR));
        },
           /**
         * Method: calculateIntersection
         * 计算两条直线的交点
         * 通过向量的思想进行计算，需要提供两个向量以及两条直线上各自一个点
         *
         * Parameters:
         * v_1 - {<Point>} 直线1的向量
         * v_2 - {<Point>} 直线2的向量
         * points1 - {<Point>} 直线1上的任意一点
         * points2 - {<Point>} 直线2上的任意一点
         *
         * Returns:
         * {Array(<SuperMap.Geometry.Point>)} 返回交点
         */
        calculateIntersection: function(v_1, v_2, point1, point2){
            //定义交点的坐标
            var x;
            var y;
            //如果向量v_1和v_2平行
            if(v_1.y*v_2.x-v_1.x*v_2.y == 0)
            {
                //平行也有两种情况
                //同向
                if(v_1.x*v_2.x>0 || v_1.y*v_2.y>0)
                {
                    //同向直接取两个点的中点
                    x = (point1.x+point2.x)/2;
                    y = (point1.y+point2.y)/2;
                }
                //反向
                else
                {
                    //如果反向直接返回后面的点位置
                    x = point2.x;
                    y = point2.y;
                }
            }
            else
            {
                //
                x = (v_1.x*v_2.x*(point2.y-point1.y)+point1.x*v_1.y*v_2.x-point2.x*v_2.y*v_1.x)/(v_1.y*v_2.x-v_1.x*v_2.y);
                if(v_1.x!=0)
                {
                    y = (x-point1.x)*v_1.y/v_1.x+point1.y;
                }
                //不可能v_1.x和v_2.x同时为0
                else
                {
                    y = (x-point2.x)*v_2.y/v_2.x+point2.y;
                }
            }
            return {x:x,y:y};

        }
};

      

       
export default DrawDiagonalArrow;